package mcache

import (
	"encoding/json"
	"github.com/allegro/bigcache/v3"
)

func IsError(err error) bool {
	return err != nil && err.Error() != "Entry not found"
}

type MemoryCacheable struct {
	BigCache *bigcache.BigCache
}

func (ce *MemoryCacheable) Get(key string) (string, error) {
	if b, err := ce.GetBytes(key); IsError(err) {
		return "", err
	} else {
		return string(b), nil
	}
}
func (ce *MemoryCacheable) GetFunc(key string, fun func() []byte) (string, error) {
	if res, err := ce.Get(key); IsError(err) {
		return "", err
	} else {
		if res == "" {
			b := fun()
			if err := ce.SetBytes(key, b); err != nil {
				return "", err
			} else {
				return string(b), nil
			}
		} else {
			return res, nil
		}
	}
}

func (ce *MemoryCacheable) GetBytes(key string) ([]byte, error) {
	if res, err := ce.BigCache.Get(key); IsError(err) {
		return nil, err
	} else {
		return res, nil
	}
}
func (ce *MemoryCacheable) GetBytesFunc(key string, fun func() []byte) ([]byte, error) {
	if res, err := ce.GetBytes(key); IsError(err) {
		return nil, err
	} else {
		if res == nil {
			b := fun()
			if err := ce.SetBytes(key, b); err != nil {
				return nil, err
			} else {
				return b, nil
			}
		} else {
			return res, nil
		}
	}
}
func (ce *MemoryCacheable) Set(key string, value string) error {
	return ce.SetBytes(key, []byte(value))
}

func (ce *MemoryCacheable) SetBytes(key string, value []byte) error {
	if err := ce.BigCache.Set(key, value); IsError(err) {
		return err
	} else {
		return nil
	}
}

func (ce *MemoryCacheable) Delete(key string) error {
	if err := ce.BigCache.Delete(key); IsError(err) {
		return err
	} else {
		return nil
	}
}

func (ce *MemoryCacheable) GetJsonFunc(key string, dest any, fun func() []byte) (any, error) {
	if res, err := ce.GetJson(key, dest); err != nil {
		return nil, err
	} else {
		if res != nil {
			return res, nil
		}
		b := fun()
		if err := ce.SetBytes(key, b); err != nil {
			return nil, err
		}
		if err := json.Unmarshal(b, dest); err != nil {
			return nil, err
		}
		return dest, nil
	}
}

func (ce *MemoryCacheable) GetJson(key string, dest any) (any, error) {
	if b, err := ce.GetBytes(key); IsError(err) {
		return nil, err
	} else {
		if b == nil {
			return nil, nil
		}
		if err := json.Unmarshal(b, dest); err == nil {
			return dest, nil
		} else {
			return nil, err
		}
	}
}

func (ce *MemoryCacheable) SetJson(key string, dest any) error {
	if b, err := json.Marshal(dest); err == nil {
		return ce.SetBytes(key, b)
	} else {
		return err
	}
}

func (ce *MemoryCacheable) Close() error {
	return ce.BigCache.Close()
}
